package cn.xd.itstack.springframework.context.support;

import cn.xd.itstack.springframework.beans.BeansException;
import cn.xd.itstack.springframework.beans.factory.ConfigurableListableBeanFactory;
import cn.xd.itstack.springframework.beans.factory.config.BeanFactoryPostProcessor;
import cn.xd.itstack.springframework.beans.factory.config.BeanPostProcessor;
import cn.xd.itstack.springframework.context.ApplicationEvent;
import cn.xd.itstack.springframework.context.ApplicationListener;
import cn.xd.itstack.springframework.context.ConfigurableApplicationContext;
import cn.xd.itstack.springframework.context.event.ApplicationEventMulticaster;
import cn.xd.itstack.springframework.context.event.ContextRefreshedEvent;
import cn.xd.itstack.springframework.context.event.SimpleApplicationEventMulticaster;
import cn.xd.itstack.springframework.core.io.DefaultResourceLoader;


import java.util.Collection;
import java.util.Map;



/**
 * @Classname AbstractApplicationContext
 * @Description TODO
 * @Date 2022/5/17 下午5:46
 * @Created by lvxiaodong
 */
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {

    public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";

    private ApplicationEventMulticaster applicationEventMulticaster;

    @Override
    public void refresh() throws BeansException{

        // 1. 创建 BeanFactory，并加载 BeanDefinition
        refreshBeanFactory();
        // 2. 获取 BeanFactory
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();

        beanFactory.addBeanPostProcessor(new ApplicationContextAwareBeanPostProcessor(this));

        // 3. 在 Bean 实例化之前，执行BeanFactoryPostProcessor (Invoke factory processors registered as beans in the context.)
        invokeBeanFactoryPostProcessors(beanFactory);

        // 4. BeanPostProcessor 需要提前于其他 Bean 对象实例化之前执行注册操作
        registerBeanPostProcessors(beanFactory);

        // 5. 提前实例化单例 Bean 对象
        beanFactory.preInstantiateSingletons();

        // 6. 初始化事件发布者
        initApplicationEventMulticaster();

        // 7. 注册事件监听器
        registerListeners();
        // 9. 发布容器刷新完成事件
        finishRefresh();





    }

    private void finishRefresh() {
        publishEvent(new ContextRefreshedEvent(this));
    }

    @Override
    public void publishEvent(ApplicationEvent event) {
        applicationEventMulticaster.multicastEvent(event);
    }

    private void registerListeners() {
        Collection<ApplicationListener> applicationListeners = getBeansOfType(ApplicationListener.class).values();
        for (ApplicationListener listener : applicationListeners) {
            applicationEventMulticaster.addApplicationListener(listener);
        }
    }

    private void initApplicationEventMulticaster() {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
        beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, applicationEventMulticaster);
    }

    /**
     * 对象实例化之前完成注册操作
     * @param beanFactory
     */
    private void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        Map<String, BeanPostProcessor> beansOfType = beanFactory.getBeansOfType(BeanPostProcessor.class);
        for (BeanPostProcessor item:beansOfType.values()) {
            beanFactory.addBeanPostProcessor(item);
        }
    }

    /**
     * 执行BeanFactoryPostProcessor
     * @param beanFactory
     */
    private void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        Map<String, BeanFactoryPostProcessor> beansOfType = beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);
        for (BeanFactoryPostProcessor item : beansOfType.values()) {
            item.postProcessBeanFactory(beanFactory);
        }

    }

    @Override
    public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {
        return getBeanFactory().getBeansOfType(type);
    }

    @Override
    public String[] getBeanDefinitionNames() {
        return getBeanFactory().getBeanDefinitionNames();
    }

    @Override
    public Object getBean(String beanName) {
        return getBeanFactory().getBean(beanName);
    }

    @Override
    public Object getBean(String beanName, Object... args) {
        return getBeanFactory().getBean(beanName,args);
    }

    @Override
    public <T> T getBean(String beanName, Class<T> requestedType) {
        return getBeanFactory().getBean(beanName,requestedType);
    }

    @Override
    public <T> T getBean(Class<T> requiredType) throws BeansException {
        return getBeanFactory().getBean(requiredType);
    }

    /**
     * 注册钩子方法
     */
    @Override
    public void registerShutdownHook(){
        Runtime.getRuntime().addShutdownHook(new Thread(this::close));
    }

    /**
     * 执行关闭
     */
    @Override
    public void close(){
        getBeanFactory().destroySingletons();
    }


    protected abstract ConfigurableListableBeanFactory getBeanFactory();

    protected abstract void refreshBeanFactory();



}
